﻿using System;
using System.Linq;
using System.ServiceModel.Description;
using System.Text;
using System.Windows.Media;
using System.Xml.Linq;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using System.Collections.Generic;

namespace VisualRibbonEditor
{
	public enum WebResourceType
	{
		Webpage_HTML = 1,
		StyleSheet_CSS = 2,
		Script_JScript = 3,
		Data_XML = 4,
		PNGformat = 5,
		JPGformat = 6,
		GIFformat = 7,
		Silverlight_XAP = 8,
		StyleSheet_XSL = 9,
		ICOformat = 10,
	}
	public enum ResourceType
	{
		All = 0,
		MarkupDocument = 1,
		CSS = 2,
		Script = 3,
		Image = 4,
		Silverlight = 5
	}
	/// <summary>
	/// Common helper methods
	/// </summary>
	public static class Helpers
	{
		const string SERVICE_PATH = "xrmservices/2011/organization.svc";

		public static ServiceWrapper GetOrgService()
		{
			return Connection.CurrentConnection.GetOrgService();
		}

		public static void GetRecordById(string entityName, Guid recordId, string[] cols, Action<Entity> callback)
		{
			var svc = GetOrgService();
			ColumnSet columns = new ColumnSet(true);
			if (cols.Length > 0) columns.AddColumns(cols);
			svc.RetrieveAsync(entityName, recordId, columns, callback);
		}

		public static void GetRecordByName(string entityName, string attributeName, object attributeValue, Action<Entity> callback, params string[] cols)
		{
			GetRecordWithCondition(entityName, attributeName, ConditionOperator.Equal, attributeValue, callback, cols);
		}

		public static void GetRecordWithCondition(string entityName, string attributeName, ConditionOperator op, object attributeValue, Action<Entity> callback, params string[] cols)
		{
			Action<EntityCollection> cb = (ec) =>
				{
					if( ec.Entities.Count > 0)
					{
						callback(ec.Entities[0]);
					}
					else
					{
						callback(null);
					}
				};

			GetRecordsWithCondition(entityName, attributeName, op, attributeValue, cb, cols);
		}

		public static void GetRecordsWithCondition(string entityName, string attributeName, ConditionOperator op, object attributeValue, Action<EntityCollection> callback, params string[] cols)
		{
			var svc = GetOrgService();

			QueryExpression q = new QueryExpression();
			 
			q.EntityName = entityName;
			q.ColumnSet = new ColumnSet();
			foreach( string col in cols)
			{
				q.ColumnSet.Columns.Add(col);
			}

			ConditionExpression c = new ConditionExpression();
			c.AttributeName = attributeName;
			c.Operator = op;
			c.Values.Add(attributeValue);
			
			q.Criteria = new FilterExpression();
			q.Criteria.Conditions.Add(c);
			 
			svc.RetrieveMultipleAsync(q, callback);
		}


		public static string AddSpaces(string s)
		{
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < s.Length; i++)
			{
				if (Char.IsUpper(s[i]) && i < s.Length - 1 && i > 1 && !char.IsUpper(s[i + 1]))
				{
					sb.Append(' ');
				}
				else if (char.IsUpper(s[i]) && i > 1 && !char.IsUpper(s[i - 1]))
				{
					sb.Append(' ');
				}

				sb.Append(s[i]);
			}

			return sb.ToString().Replace("  ", " ").Trim();
		}

		/// <summary>
		/// Get color from hex. format = "#AARRGGBB"
		/// </summary>
		public static Color GetColorFromHexa(string hexaColor)
		{
			if (hexaColor.Length == 6) //RRGGBB
				hexaColor = "#FF" + hexaColor;
			if (hexaColor.Length == 8) //AARRGGBB
				hexaColor = "#" + hexaColor;
			if (hexaColor.Length == 7 && hexaColor.StartsWith("#")) //#RRGGBB
				hexaColor = "#FF" + hexaColor.Substring(1);
			  
			if (hexaColor.Length != 9)
			{
				throw new Exception("GetColorFromHexa incorrect format");
			}

			return
				Color.FromArgb(
					Convert.ToByte(hexaColor.Substring(1, 2), 16),
					Convert.ToByte(hexaColor.Substring(3, 2), 16),
					Convert.ToByte(hexaColor.Substring(5, 2), 16),
					Convert.ToByte(hexaColor.Substring(7, 2), 16)
				);
		}

		public static string GetLocLabelTextById(string id, string language)
		{
			string text = null;
			XElement LocLabel = MainWindow.CurrentSolution.RibbonDiffXml.Descendants("LocLabel").Where(x => x.Attribute("Id") != null && x.AttributeValue("Id") == id).FirstOrDefault();

			if (LocLabel != null)
			{
				XElement Title = LocLabel.Descendants("Title").Where(x => x.Attribute("languagecode") != null && x.AttributeValue("languagecode") == language).FirstOrDefault();
				if (Title == null) Title = LocLabel.Descendants("Title").Where(x => x.Attribute("languagecode").Value == Connection.CurrentConnection.BaseLanguage).FirstOrDefault();
				
				if (Title != null)
				{
					text = Title.AttributeValue("description");
				}
			}
			return text;
		}

	 
		public static void SetLocLabelTextById(string id, string language, string text)
		{
			XElement LocLabels = MainWindow.CurrentSolution.RibbonDiffXml.Descendants("LocLabels").FirstOrDefault();

			XElement LocLabel = LocLabels.Elements().Where(x => x.Attribute("Id").Value == id).FirstOrDefault();
			if (LocLabel == null)
			{
				//add new label if doesnt exist yet
				LocLabel = new XElement("LocLabel");
				LocLabel.SetAttributeValue("Id", id);
				LocLabels.Add(LocLabel);
				XElement newTitles = new XElement("Titles");
				LocLabel.Add(newTitles);
			}

			XElement Titles = LocLabel.Element("Titles");
			XElement Title = Titles.Elements().Where(x => x.AttributeValue("languagecode") == language).FirstOrDefault();
			if (Title == null)
			{
				//add title if doesnt exist yet.
				Title = new XElement("Title");
				Title.SetAttributeValue("languagecode", language);
				Titles.Add(Title);
			}

			string oldValue = Title.AttributeValue("description");// GetAttributeValue(Title, "description");
			if (oldValue != text)
			{
				Title.SetAttributeValue("description", text);
				MainWindow.CurrentMainPage.RenderRibbon();
			}
		}


		public static bool IsButtonEditable(string buttonId)
		{
			XElement button = MainWindow.CurrentSolution.RibbonDiffXml
				.Element("CustomActions")
				.Descendants("Button")
				.Where(x => x.Attribute("Id").Value == buttonId)
				.FirstOrDefault();

			return (button != null);
		}

		public static bool IsGroupEditable(string groupId)
		{
			XElement button = MainWindow.CurrentSolution.RibbonDiffXml
				.Element("CustomActions")
				.Descendants("Group")
				.Where(x => x.Attribute("Id").Value == groupId)
				.FirstOrDefault();

			return (button != null);
		}

		public static void AddCustomActionToDiffXml(XElement control)
		{
			if (MainWindow.CurrentSolution == null) { throw new Exception("AddCustomActionToDiffXml called when no solution loaded."); }

			XElement customActions = MainWindow.CurrentSolution.RibbonDiffXml.Element("CustomActions");

			string controlId = control.AttributeValue("Id");
			string parentId = control.Parent.AttributeValue("Id");
			XElement controlCopy = XElement.Parse(control.ToString());

			//add the customAction element
			XElement newCustomAction = new XElement("CustomAction");
			newCustomAction.SetAttributeValue("Id", controlId + ".CustomAction");
			newCustomAction.SetAttributeValue("Location", parentId + "._children");
			newCustomAction.SetAttributeValue("Sequence", "10");
			customActions.Add(newCustomAction);

			//add the commandUIDefinition element
			XElement commandUIDefinition = new XElement("CommandUIDefinition");
			newCustomAction.Add(commandUIDefinition);

			//add the control to the commandUIDefinition
			commandUIDefinition.Add(controlCopy);
		}


		public static string AttributeValue(this XElement element, string attributeName)
		{
			XAttribute att = element.Attribute(attributeName);
			if (att != null)
			{
				return att.Value;
			}
			else
			{
				return null;
			}
		}

		public static List<XElement> GetGroupControlsOrdered( XElement group )
		{
			List<XElement> controlList = new List<XElement>();

			XElement controls = group.Element("Controls");

			string templateId = group.AttributeValue("Template");
			XElement root = group.Ancestors().Last();
			XElement groupTemplate = root.Descendants("GroupTemplate").Where(x => x.AttributeValue("Id") == templateId).FirstOrDefault();
			if (groupTemplate != null)
			{
				XElement layout = groupTemplate.Elements("Layout").FirstOrDefault();
				if (layout != null)
				{
					//iterate through each templateAlias in the order they appear in the template layout
					foreach (XAttribute ta in layout.Descendants().Attributes("TemplateAlias"))
					{
						string templateAlias = ta.Value;
						//iterate through each control that uses this templateAlias
						foreach (XElement control in controls.Elements()
							.Where(x => x.AttributeValue("TemplateAlias") == templateAlias).OrderBy(SortElements))
						{
							controlList.Add(control);
						}
					}
				}
			}

			return controlList;
		}


		/// <summary>
		/// Element sorting function (sorts based on sequence attribute)
		/// </summary>
		private static string SortElements(XElement el)
		{
			XAttribute seq = el.Attribute("Sequence");
			if (seq != null)
			{
				int seqInt = int.Parse(seq.Value);
				return string.Format("{0:00000.00}", seqInt);
			}
			return string.Empty;
		}
	}
}
